#pragma once
#include <iostream>
#include <cstring>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <pthread.h>
#include <memory>

#include "log.hpp"
#include "InetAddr.hpp"

const static int listennum = 8;


struct Socket;
using SockSPtr = std::shared_ptr<Socket>;
struct Socket
{
	virtual void CreateSocket() = 0;
	virtual void BindSocket(uint16_t port) = 0;
	virtual void CreateListen(int num = listennum) = 0;
	virtual bool  Connecter(const std::string serverip,uint16_t serverport) = 0;
	virtual int Accepter(InetAddr* client) = 0;
	virtual ssize_t  Recv(std::string* out) = 0;
	virtual ssize_t Send(const std::string& in) = 0;
	virtual int Sockfd() = 0;
        virtual void Close() = 0;
	void BuildListenSocket(uint16_t port)
	{
		CreateSocket();
		BindSocket(port);
		CreateListen();
	};
	bool BuildClientSocket(const std::string serverip,uint16_t serverport)
	{
		CreateSocket();
		return Connecter(serverip,serverport);
	};
};
class TcpSocket :public Socket
{
public:
	TcpSocket()
	{
	};
	TcpSocket(int sockfd):_sockfd(sockfd)
	{
	};
	virtual void CreateSocket() override
	{
		_sockfd = socket(AF_INET,SOCK_STREAM,0);
		if(_sockfd<0)
		{
			LOG(FATAL,"CreateSocket err\n");
			exit(1);
		};
	};
        virtual void BindSocket(uint16_t port) override
	{
		struct sockaddr_in localaddr;
		memset(&localaddr,0,sizeof(localaddr));
		localaddr.sin_family =AF_INET;
		localaddr.sin_port=htons(port);
		localaddr.sin_addr.s_addr =INADDR_ANY;
		int n =bind(_sockfd,reinterpret_cast<struct sockaddr*>(&localaddr),sizeof(localaddr));
		if (n < 0)
       	 	{
            		LOG(FATAL, "BindSocket error\n");
      		      exit(2);
       		 }
       		 LOG(DEBUG, "BindSocket success\n");
	};
        virtual void CreateListen(int num = listennum) override
	{
		 if(::listen(_sockfd,listennum)<0)
		 {
            		LOG(FATAL, "CreateListen error\n");
      		      exit(3);
		 }
       		 LOG(DEBUG, "CreateListen success\n");
	};
        virtual bool  Connecter(const std::string serverip,uint16_t serverport) override
	{
		struct sockaddr_in server;
    		server.sin_family= AF_INET;
	    server.sin_port =htons(serverport);
	    inet_pton(AF_INET,serverip.c_str(),&server.sin_addr.s_addr);
	    if(connect(_sockfd,(struct sockaddr*)&server,sizeof(server))<0)
	    {
		    LOG(FATAL,"client connect  err\n");
	                return false;
	    };
	    return true;
	};
        virtual int Accepter(InetAddr* client) override
	{
		struct sockaddr_in clientaddr;
		socklen_t len = sizeof(clientaddr);
		int sockfd = accept(_sockfd,(struct sockaddr*)&clientaddr,&len);
		if(sockfd<0)
		{
			LOG(WARNING,"Accepter err\n");
			return -1;
		};
		*client=InetAddr(clientaddr);
		LOG(INFO, "get a new link, client info : %s, sockfd is : %d\n", (*client).AddrStr().c_str(), sockfd);
		return sockfd;
	};
	int Sockfd()
	{return _sockfd;};
	void Close()
	{
		if(_sockfd>0)
			close(_sockfd);
	};
        virtual ssize_t Recv(std::string* out) override
	{
		char buffer[1024];//字节流当字符串使用
		ssize_t n =recv(_sockfd,buffer,sizeof(buffer)-1,0);
		if(n>0)
		{
			LOG(DEBUG,"Recv success\n");
			buffer[n] = 0;//恢复字符串
			*out +=buffer;
		}
		return n;
	}
        virtual ssize_t Send(const std::string& in) override
	{
		return send(_sockfd,in.c_str(),in.size(),0);
	};

private:
	int _sockfd;
	
};
